"""
07_memory_persistence.py - Memory and Persistence
===================================================
Chapter 9: Making agents remember across conversations.

KEY CONCEPTS:
  ★ MemorySaver - In-memory checkpointer
  ★ thread_id - Unique conversation identifier
  ★ Separate threads = separate conversations
  ★ State persists between invoke() calls

Run: python src/07_memory_persistence.py
"""
from typing import TypedDict, Annotated
from operator import add
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import MemorySaver

class MemoryState(TypedDict):
    messages: Annotated[list, add]
    message_count: int

def process_message(state: MemoryState) -> dict:
    count = len(state.get("messages", []))
    last = state["messages"][-1] if state["messages"] else ""
    reply = f"[Bot msg#{count}] You said: {last}"
    return {"messages": [reply], "message_count": count + 1}

graph = StateGraph(MemoryState)
graph.add_node("bot", process_message)
graph.add_edge(START, "bot")
graph.add_edge("bot", END)
checkpointer = MemorySaver()
app = graph.compile(checkpointer=checkpointer)

if __name__ == "__main__":
    print("=" * 60)
    print("07: Memory and Persistence")
    print("=" * 60)
    
    # Thread 1: Alice's conversation
    config_alice = {"configurable": {"thread_id": "alice_123"}}
    r1 = app.invoke({"messages": ["Hello, I'm Alice!"]}, config=config_alice)
    r2 = app.invoke({"messages": ["What's LangGraph?"]}, config=config_alice)
    print(f"\n  Alice's messages ({len(r2['messages'])} total):")
    for m in r2["messages"]:
        print(f"    {m}")
    
    # Thread 2: Bob's separate conversation
    config_bob = {"configurable": {"thread_id": "bob_456"}}
    r3 = app.invoke({"messages": ["Hi, I'm Bob!"]}, config=config_bob)
    print(f"\n  Bob's messages ({len(r3['messages'])} total):")
    for m in r3["messages"]:
        print(f"    {m}")
    
    print(f"\n  Alice has {len(r2['messages'])} msgs, Bob has {len(r3['messages'])} msgs")
    print(f"  They are SEPARATE threads!")
    print(f"\n{'=' * 60}\n✅ Memory and persistence complete!")
